home *** CD-ROM | disk | FTP | other *** search
- ;$VER: MyMouse.asm 1.2 (12.02.93)
- ;Written by Andrew Forrest
- ;Based on QMouse by Dan Babcock
-
- ;Assembled with Devpac 3
- nolist
-
- ; How it works:
- ; The program spawns a child process which remains resident in memory and
- ; does the funky stuff. If the resident process already exists, the program
- ; alters the child's parameters and sends it an update signal. The main
- ; program allocates stuff that's _always_ needed, the child allocates other
- ; stuff on the fly (input.device, for example).
-
- ; While it is setting up, the child makes itself invisible by changing its
- ; name. This ensures that a seach for the child (by name) will always find
- ; the child prepared.
-
- ; PROCESS IS GUARUNTEED TO STAY PUT (cos you can't totally unpatch functions)
-
- include everything.i
- include hardware/dmabits.i
-
- Execbase equ 4
- _custom equ $dff000
-
- ;*»» Semaphore macros
- ; Use carefully!
- ; Take a5=GlobalPtr; a6=ExecBase
- ; Scratch a0
- CriticalSection macro
- lea MySemaphore(a5),a0
- just ObtainSemaphore
- endm
- EndCritical macro
- lea MySemaphore(a5),a0
- just ReleaseSemaphore
- endm
-
- BlankScreen macro
- move.w #DMAF_COPPER+DMAF_RASTER,dmacon+_custom.l
- clr.w color+_custom.l
- endm
- UnBkScreen macro
- move.w #DMAF_SETCLR+DMAF_COPPER+DMAF_RASTER,dmacon+_custom.l
- endm
-
- ;*»» Code entrypoint
- move.l Execbase,a6
- cmp.w #37,LIB_VERSION(a6)
- bhs GoodVersion
-
- ;Oh no, we're running under 1.3 or something
- lea DosName(pc),a1
- moveq.l #0,d0
- just OpenLibrary
- tst.l d0
- beq.s ErrorEnd
- move.l d0,a6
- just Output
- move.l d0,d1
- moveq #SorryLength,d3
- lea Sorry(pc),a0
- move.l a0,d2
- just Write
- move.l a6,a1
- move.l Execbase,a6
- just CloseLibrary
- ErrorEnd: moveq #RETURN_FAIL,d0
- rts
-
- dc.b '$VER: MyMouse 1.2 (08.02.94)',LF,0
-
- Sorry dc.b 'You need (at least) Kickstart 2.0 to run this program.',LF,0
- SorryLength equ *-Sorry
- even
-
- GoodVersion:
- ***************************************************************************
- * Start of Main program
- ***************************************************************************
- ; Registers:
- ; A5=^Global data structure
- ; D7=^Installed process, _if it exists yet_, else NULL
-
- lea ProcName(pc),a1
- just FindTask
- move.l d0,d7
- bne.s .else ; If process doesn't exist then
- bsr Allocate ; Reserve some space for it
- bne Deallocate
- bsr.s Read_Args ; (returns Z flag success)
- bne Deallocate
- bsr Install ; (returns pointer to new task)
- beq Deallocate
- bra.s .end_ok ; else
- .else move.l d7,a1
- move.l TC_Userdata(a1),a5 ; Get global structure
- bsr.s Read_Args
- bne.s .end_fail ;(If couldn't read args, fail)
- move.l d7,a1
- move.l UpdateSig(a5),d0
- just Signal ; Send task a signal to wake it up
- .end_ok moveq #RETURN_OK,d0
- .end_fail rts
-
- ***************************************************************************
- Read_Args: ;*»» Replace arguments in global structure with new ones
- ; Takes a5=GlobalPtr; Returns OK or FAIL code; a6=Execbase
- ; Scratches d0-d4/a0-a1/a4
- CriticalSection
- lea Template(pc),a0
- move.l a0,d1
- lea Options(a5),a0
- move.l a0,d2
- moveq #NumOptions-1,d0
- .clear_loop clr.l (a0)+
- dbra d0,.clear_loop
- moveq #0,d3 ;no custom rdarg structure
- move.l DosBase(a5),a6
- just ReadArgs
- tst.l d0
- beq.s .fail
- move.l ArgPtr(a5),d1 ; get _old_ arguments
- beq.s .use
- push.l d0
- just FreeArgs ; and free them if necessary
- pop.l d0
- .use move.l d0,ArgPtr(a5) ; then install _new_ arguments
- move.l Execbase,a6
- moveq.l #RETURN_OK,d0
-
- .end EndCritical
- tst.l d0 ; (return D0 and CCR)
- rts
-
- .fail move.l Execbase,a6
- moveq.l #RETURN_FAIL,d0
- bra.s .end
-
- ***************************************************************************
- Install:
- ; Takes a5=GlobalPtr; a6=Execbase; Returns d0=^NewTask or NULL
- ; Scratches a0-a1/d0-d1
- ;*»» Copy resident part of code into allocated memory
- lea StartResidentCode(pc),a0 ;source
- lea ResidentCode(a5),a1 ;destination
- move.l #ResidentCodeLength,d0 ;size
- just CopyMem
- just CacheClearU ;for 020/030/040
-
- ;*»» Initialize static data
- move.b #HANDLERPRI,InputInterrupt+LN_PRI(a5)
- move.l a5,InputInterrupt+IS_DATA(a5)
- lea IntRoutine-StartResidentCode+ResidentCode(a5),a0
- move.l a0,InputInterrupt+IS_CODE(a5)
-
- move.l a5,GlobalPtr-StartResidentCode+ResidentCode(a5)
-
- ;*»» Get stack for command.
- move.l DosBase(a5),a6
- just Cli
- move.l d0,a0
- move.l cli_DefaultStack(a0),d0
- lsl.l #2,d0
- move.l d0,CmdStackSize-StartResidentCode+ResidentCode(a5)
-
- ;*»» Start the baby process
- lea NewProcTags-StartResidentCode+ResidentCode(a5),a0
- lea NEW_LIFE-StartResidentCode+ResidentCode(a5),a1
- move.l a1,EntryPointTag(a0)
- lea ProcName-StartResidentCode+ResidentCode(a5),a1
- not.b (a1) ; (So task is initially invisible)
- move.l a1,ProcNameTag(a0)
- move.l a0,d1 ; Get tag list into d1
- just CreateNewProc
- tst.l d0
-
- move.l Execbase,a6
- rts
-
- ***************************************************************************
- Allocate:
- ; Takes a6=Execbase; Returns OK or FAIL; a5=GlobalPtr or NULL
- ; Scratches a0-a3/d0-d1
- ;*»» Allocate global data structure
- move.l #Data_SIZEOF,d0
- move.l #MEMF_CLEAR|MEMF_PUBLIC,d1 ;(Got to be PUBLIC)
- just AllocMem
- move.l d0,a5 ; Need to store in a5 _before_ testing
- tst.l d0
- beq.s .cant_alloc
-
- ;*»» Allocate Chip RAM data
- move.l #MouseData_SIZEOF,d0
- move.l #MEMF_CLEAR|MEMF_PUBLIC|MEMF_CHIP,d1
- just AllocMem
- move.l d0,MouseChipData(a5)
- beq.s .cant_alloc
-
- ;*»» Open libraries
- lea LibTable(pc),a2
- lea FirstLibBase(a5),a3
- moveq #NumLibs-1,d2
- .loop move.w (a2)+,d0 ; library version to open
- ext.l d0 ; version should be longword
- move.w (a2)+,a1
- lea LibTable(pc,a1.w),a1 ; name of library
- just OpenLibrary
- move.l d0,(a3)+
- beq.s .cant_alloc
- dbra d2,.loop
-
- ;*»» Set up semaphore
- lea MySemaphore(a5),a0
- just InitSemaphore
-
- moveq #RETURN_OK,d0 ; Set d0 and CCR
- rts
-
- .cant_alloc moveq #RETURN_FAIL,d0
- rts
-
- ***************************************************************************
- LibTable: dc.w 37,DosName-LibTable
- dc.w 33,IntName-LibTable
- dc.w 33,LayName-LibTable
- NumLibs: equ (*-LibTable)/4
-
- ***************************************************************************
- ***************************************************************************
- StartResidentCode: ;The following code is copied into allocated memory.
- ***************************************************************************
- ; Everything except Deallocate is called only from child process
- ***************************************************************************
- Deallocate: ;*»» Close libraries (called either from parent or child)
- ; Takes a5=GlobalPtr; a6=Execbase; No return value.
- ; Scratches a0-a2/d0-d2
- move.l a5,d0 ; Does global structure exist?
- beq.s .noData
-
- lea FirstLibBase(a5),a2
- moveq #NumLibs-1,d2
- .loop move.l (a2)+,d0
- beq.s .endif
- move.l d0,a1
- just CloseLibrary
- .endif dbra d2,.loop
-
- ;*»» Free chip data.
- move.l MouseChipData(a5),d0
- beq.s .noChipData
- move.l d0,a1
- move.l #MouseData_SIZEOF,d0
- just FreeMem
- .noChipData
- ;*»» Free global structure
- lea (a5),a1
- move.l #Data_SIZEOF,d0
- jmp _LVOFreeMem(a6) ; Jump in case we are
- .noData ; deallocating _this_ code
- rts
-
- ***************************************************************************
- ; Here lies the start of the child process' program
- ; Except where noted, subroutines should preserve a5-a6 (and the stack
- ; pointer of course), but may trash other registers
- NEW_LIFE: move.l Execbase,a6
- move.l GlobalPtr(pc),a5
- bsr InitialiseResident ; Get signals
- bne.s Deallocate ; (_not_ a branch to subrtn)
-
- BIG_LOOP: bsr EvaluateOptions
- bne.s KillHandler
- bsr AllocateResident ; Get so far ungot resources
- wait_loop: move.l AllSignals(a5),d0
- just Wait ; \ Routines called from this section
- move.l d0,d7 ; / may trash any register except a5 or d7
- and.l CLISig(a5),d0
- beq.s .noCLI
- * move.l Execbase,a6 (already the case)
- bsr CLI ; Expects a6=Execbase (nobody's perfect:-)
- .noCLI move.l d7,d0
- and.l MouseBlankSig(a5),d0
- beq.s .noMB
- bsr MouseBlankUpdate
- .noMB tst.l ActivateScreenOption(a5)
- beq.s .noActiWind ; If window-activation is off anyway then
- move.l d7,d0 ; ...don't bother to check for the signals
- and.l CloseScreenSig(a5),d0
- beq.s .noClose
- bsr Closure
- .noClose move.l d7,d0
- and.l ScreenDepthSig(a5),d0
- beq.s .noDepth
- bsr.s Depth
- .noDepth
- .noActiWind move.l Execbase,a6
- and.l UpdateSig(a5),d7
- beq.s wait_loop
- bra.s BIG_LOOP
-
- KillHandler:
- bclr #STB_HandlerInstalled,Status(a5)
- beq.s .end
- move.l InputIORequest(a5),a1
- move.w #IND_REMHANDLER,IO_COMMAND(a1)
- lea InputInterrupt(a5),a0
- move.l a0,IO_DATA(a1)
- just DoIO
- bclr #STB_DoMBlank,Status(a5)
- bsr MouseBlankUpdate ; Switch off mouse-blanking
- bclr #STB_SBlanked,Status(a5)
- UnBkScreen ; Switch off screen-blanking
- .end bra.s wait_loop
-
- ;****************************************************************************
- ; This routine is called asynchronously whenever Intuition's ScreenDepth
- ; routine gets called (i.e. any time a screen is rearranged).
- Depth: move.l IntBase(a5),a6
- moveq #0,d0
- just LockIBase ; Start critical section
- move.l d0,d2
- move.l ib_ActiveScreen(a6),a0 ; \ Remember to keep track
- move.l ib_ActiveWindow(a6),a1 ; | of _previous_ screen-
- bsr AssociateWindow ; / window combination
- move.l ib_FirstScreen(a6),a0 ; \ Look up `active' window
- bsr IndexScreenTable ; / of newly frontmost screen
- tst.l d0
- beq.s .fail ; If we can find a window for screen,
- move.l d0,a0 ; ...then activate that window
- just ActivateWindow ; (Defered so should be OK inside lock)
- .fail move.l d2,a0
- just UnlockIBase ; End critical section
- rts
-
- ; This one gets called on screen closure.
- Closure: move.l IntBase(a5),a6
- moveq #0,d0
- just LockIBase ; Start critical section
- move.l d0,a0
- bsr PruneScreenTable ; (Alters no registers)
- just UnlockIBase ; End critical section
- or.l ScreenDepthSig(a5),d7 ; (Must change window too)
- rts
-
- ; Executes a CLI command (like NewShell, for example)
- ; *** Expects a6=Execbase
- CLI: CriticalSection ; Critical so CMD parameter can't change
- move.l CmdOption(a5),d1 ;Pop CLI
- beq.s .fail
- pushm.l d1/a6
- move.l IntBase(a5),a6 ;Workbench To Front
- just WBenchToFront
- popm.l d1/a6
- move.l DosBase(a5),a6
- lea Tags(pc),a1
- bsr.s OpenNil
- move.l d0,InputTag(a1)
- beq.s .end
- bsr.s OpenNil
- move.l d0,OutputTag(a1)
- beq.s .closeinput
- move.l a1,d2 ;tags
- just SystemTagList
- tst.l d0
- beq.s .end ; If sucessful, should deallocate itself
- move.l OutputTag+Tags(pc),d1
- just Close
- .closeinput move.l InputTag+Tags(pc),d1
- just Close
- .end move.l Execbase,a6
- .fail EndCritical
- rts
-
- Tags:
- dc.l SYS_UserShell,0
- dc.l SYS_Asynch,0
- dc.l SYS_Input,0
- InputTag equ *-4-Tags
- dc.l SYS_Output,0
- OutputTag equ *-4-Tags
- dc.l NP_Priority,ShellPriority
- dc.l NP_StackSize
- CmdStackSize:
- dc.l 0
- dc.l 0 ;end of tag list
-
- OpenNil: pushm.l a0-a1/d1-d2
- lea NilName(pc),a0
- move.l a0,d1
- move.l #MODE_READWRITE,d2
- just Open
- popm.l a0-a1/d1-d2
- rts
-
- ;****************************************************************************
- InitialiseResident:
- ; Takes a5=GlobalPtr; a6=Execbase; Returns OK or FAIL
- ; Scratches d0-d2/a0-a1
- suba.l a1,a1
- just FindTask ; _Find_ yourself.
- move.l d0,a0
- move.l a5,TC_Userdata(a0)
- move.l d0,Task(a5)
- bsr InitialiseScreenTable ; Just set it up
-
- ;*»» Allocate signals
- moveq #NumSigs-1,d2
- lea Sigs(a5),a2
- .sigloop moveq #-1,d0
- just AllocSignal
- tst.l d0
- bmi.s .fail
- .ok moveq #0,d1
- bset d0,d1
- move.l d1,(a2)+
- or.l d1,AllSignals(a5)
- dbra d2,.sigloop
-
- just Forbid
- lea ProcName(pc),a1
- move.b #InitialLetter,(a1)
- just FindTask ; Search for process with same name
- tst.l d0
- bne.s .found_twin ; Oh, no -- duplicate name
- move.l Task(a5),a1
- move.l LN_NAME(a1),a1
- move.b #InitialLetter,(a1) ; make process visible
- just Permit
-
- ;*»» Patch three Intuition routines. (Do this last)
- ;*»» (all but first patch must be on V39 library)
- lea PatchTable(pc),a2
- lea OldRoutines(a5),a3
- move.l IntBase(a5),a1 ; Library to patch
- .patchloop move.w (a2)+,d1 ; LVO offset
- beq.s .endpatch ; (exit if hit null-terminator)
- move.w (a2)+,d0 ; Offset to new routine
- tst.l (a3) ; If it is already patched
- bne.s .nextpatch ; skip to the next one
- lea PatchTable(pc,d0.w),a0 ; Get address of new routine
- move.l a0,d0 ; d0 <- address of new routine
- move.w d1,a0 ; a0 <- LVO offset
- just SetFunction
- move.l d0,(a3)+ ; Store ^old routine for posterity
- .nextpatch move.l IntBase(a5),a1 ;\ Get ^Intuition for next
- cmp.w #39,LIB_VERSION(a1) ;/ iteration and check version
- bhs.s .patchloop ; Patch V39 Intuition only
- .endpatch
-
- moveq #RETURN_OK,d0
- rts
-
- .found_twin
- .fail moveq #31,d2
- .loop btst d2,AllSignals(a5)
- beq.s .next
- move.l d2,d0
- just FreeSignal
- .next dbra d2,.loop
- moveq #RETURN_FAIL,d0
- rts
-
- PatchTable: dc.w _LVODisplayBeep,NewDisplayBeep-PatchTable
- dc.w _LVOCloseScreen,NewCloseScreen-PatchTable
- dc.w _LVOScreenDepth,NewScreenDepth-PatchTable
- dc.w 0 ; NULL-terminate list
-
- ***************************************************************************
- NewDisplayBeep:
- move.l GlobalPtr(pc),a1
- tst.l NoBeepOption(a1)
- bne.s .endif
- move.l OldDisplayBeep(a1),-(sp)
- .endif rts
-
- NewCloseScreen:
- pushm.l a2/a5-a6
- move.l GlobalPtr(pc),a5
- move.l OldCloseScreen(a5),a2
- jsr (a2)
- move.l d0,a2 ; (Preserve return value)
- move.l CloseScreenSig(a5),d0
- bra.s sig
-
- NewScreenDepth:
- pushm.l a2/a5-a6
- move.l GlobalPtr(pc),a5
- move.l OldScreenDepth(a5),a2
- jsr (a2)
- move.l ScreenDepthSig(a5),d0
-
- sig move.l Task(a5),a1
- move.l Execbase,a6
- just Signal
- move.l a2,d0 ; (Restore return value)
- popm.l a2/a5-a6
- rts
-
-
- ***************************************************************************
- ; Here is the routine for allocating the baby task's resources
- ; If they cannot be allocated at first, the program tries again every time
- ; an update signal is recieved.
- AllocateResident:
- ; Takes a5=GlobalPtr; a6=Execbase
- ; Scratches a0-a3/d0-d1
- ;*»» Create an IORequest structure
- move.l InputMsgPort(a5),d0
- bne.s .endCreatePort ; Skip if port already there
- just CreateMsgPort
- move.l d0,InputMsgPort(a5)
- beq.s .fail
- .endCreatePort
- move.l d0,a0
- move.l InputIORequest(a5),d0 ; n.b. _not_ "tst.l Inpu..."
- bne.s .endCreateReq ; Skip if req already there
- moveq #IOSTD_SIZE,d0
- just CreateIORequest
- move.l d0,InputIORequest(a5)
- beq.s .fail
- .endCreateReq
-
- ;*»» Open the input.device
- btst #STB_InputDeviceOpened,Status(a5)
- bne.s .endOpenInput
- move.l d0,a1 ;IO request
- lea InputName(pc),a0 ;device name
- moveq #0,d0 ;unit number
- moveq #0,d1 ;flags
- just OpenDevice
- tst.l d0
- bne.s .fail
- bset #STB_InputDeviceOpened,Status(a5)
- .endOpenInput
-
- ;*»» Install the input handler
- bset #STB_HandlerInstalled,Status(a5)
- bne.s .endInstallHandl
- move.l InputIORequest(a5),a1
- move.w #IND_ADDHANDLER,IO_COMMAND(a1)
- lea InputInterrupt(a5),a0
- move.l a0,IO_DATA(a1)
- just DoIO
- .endInstallHandl
-
- .fail rts
-
- ***************************************************************************
- EvaluateOptions:
- ; Takes a5=GlobalPtr; a6=Execbase; Scratches d0-d1/a0-a2
- ;*»» Copy some parameters (for input-handler)
- CriticalSection ; So no one changes them while we do it
- lea CacheTable(pc),a1
- lea OptionCaches(a5),a2
- move.w #CacheNum-1,d1
- .loop move.w (a1)+,d0
- move.l (a5,d0.w),d0
- .if beq.s .else
- move.l d0,a0
- move.l (a0),d0
- bra.s .endif
- .else moveq #-1,d0 ; Unselected options become -1
- .endif move.l d0,(a2)+
- dbra d1,.loop
- .endloop EndCritical
-
- ;*»» Ensure mouse/screen is never left blanked
- tst.l MouseBlank(a5)
- bge.s .mblnk_on ; Skip if mouse blanking was turned on
- bclr #STB_DoMBlank,Status(a5)
- bsr MouseBlankUpdate
- .mblnk_on tst.l ScreenBlank(a5)
- bgt.s .sblnk_on ; Skip if screen blanking was turned on
- bclr #STB_SBlanked,Status(a5)
- UnBkScreen
- .sblnk_on
-
- ;*»» Initialize damping constant.
- move.l Acceleration(a5),d0
- bmi.s .no_damp
- move.l d0,a0
- move.l (a0),d0
- subq.l #1,d0
- move.l Threshold(a5),d1
- bpl.s .use_thresh
- moveq #0,d1
- .use_thresh addq.l #1,d1
- mulu.w d0,d1
- move.w d1,DampingConstant(a5)
- .no_damp
- .okay
- *»» Check that at least one command-line option was specified
- lea Options(a5),a0
- moveq #NumOptions-1,d0
- .chk_loop tst.l (a0)+
- bne.s .dontdie
- dbra d0,.chk_loop
- bsr ShutDownScreenTable ; If no options deallocate mem
- moveq #RETURN_FAIL,d0 ; Return nonzero if no options
- rts
- .dontdie moveq #RETURN_OK,d0 ; Return zero if at least 1 selected
- rts
-
- CacheTable dc.w MBlankOption
- dc.w SBlankOption
- dc.w AccelOption
- dc.w ThreshOption
- dc.w CTFOption
- dc.w ClickBorderOption
- CacheNum equ (*-CacheTable)/2
-
- ;****************************************************************************
- include MM-Handler.asm
- include ScreenTable.asm
-
- ;****************************************************************************
- ;Utility routines
-
- ;*»» Get window associated with current mouse position.
- ; Takes a5=GlobalPtr; a6=IntBase; Returns d0=Window; D1=Screen
- ; (assume we don't need to lock IntuitionBase)
- GetWindow:
- pushm.l d4/a0-a1/a4/a6
- lea (a6),a4
- move.l LayBase(a5),a6
- move.l ib_FirstScreen(a4),d4
- .loop tst.l d4
- beq.s .err_end
- move.l d4,a0
- move.l sc_NextScreen(a0),d4
- move.w sc_MouseX(a0),d0
- bmi.s .loop
- move.w sc_MouseY(a0),d1
- bmi.s .loop
- push.l a0
- lea sc_LayerInfo(a0),a0
- just WhichLayer
- pop.l d1
- tst.l d0
- beq.s .end
- move.l d0,a0
- move.l lr_Window(a0),d0
- .end popm.l d4/a0-a1/a4/a6
- rts
- .err_end: moveq #0,d0
- moveq #0,d1
- bra .end
-
- DoWindowToFront:
- ; Takes d0=^Window or NULL (no effect); a5=GlobalPtr
- ; scratches nothing
- tst.l d0
- beq.s .abort
- pushm.l d0-d1/a0-a1/a6
- move.l IntBase(a5),a6
- move.l d0,a0
- move.l wd_WLayer(a0),d0
- beq.s .end
- move.l d0,a1
- move.l lr_ClipRect(a1),d0
- beq.s .end
- move.l d0,a1
- tst.l cr_Next(a1) ; Do nothing if it is not covered
- beq.s .end
- move.l wd_Flags(a0),d0
- and.l #WFLG_BACKDROP,d0
- bne.s .end ; or if it is a backdrop window
- just WindowToFront
- .end popm.l d0-d1/a0-a1/a6
- .abort rts
-
- ; Blank or unblank the mouse, depending on Globals.Status.DoMBlank.
- ; Takes nil (but needs a5=^Globals); Trashes/Returns nil;
- ; NEVER call with Intbase locked
- MouseBlankUpdate:
- pushm.l a0-a1/a6/d0-d2
- move.l IntBase(a5),a6
- moveq #0,d0
- just LockIBase ; *** Critical section
- move.l d0,d2
- move.l Execbase,a6
- just Forbid ; (make sure no one changes mouse)
- btst #STB_DoMBlank,Status(a5)
- beq.s .restore
- .blank bsr BlankMouse
- bra.s .endif
- .restore bsr RestoreMouse
- .endif just Permit ; (allow other tasks)
- move.l d2,a0
- move.l IntBase(a5),a6
- just UnlockIBase ; *** End critical section
- popm.l a0-a1/a6/d0-d2
- rts
-
- ;*»» Blank the current window's mouse pointer
- ; Takes a5=GlobalPtr; IBase must be locked; Scratches nothing
- BlankMouse: pushm.l a0-a1/a6/d0-d3
- move.l IntBase(a5),a6
- move.l ib_ActiveWindow(a6),a0
- cmp.l MBlankWindow(a5),a0
- beq.s .same_wind ; If a different window is now active then
- .other_win bsr.s RestoreMouse ; unblank it first
- bra.s .notblanked ; Else
- .same_wind move.l wd_Pointer(a0),d0
- cmp.l MouseChipData(a5),d0 ; If still blanked, give up
- beq.s .end_blank
- .notblanked move.l a0,MBlankWindow(a5) ; Remember window & its pointer
- beq.s .no_blank ; Quit if no current window(!)
- move.l wd_WScreen(a0),MBlankScreen(a5) ; Remember screen
- clr.l OldPointer+Ptr_Image(a5) ; Assume no custom image
- move.l wd_Pointer(a0),d0
- cmp.l MouseChipData(a5),d0
- beq.s .end_blank ; Quit if already blanked
- move.l d0,OldPointer+Ptr_Image(a5)
- move.l wd_PtrDimensions(a0),OldPointer+Ptr_Dimensions(a5)
- move.l MouseChipData(a5),a1
- moveq #1,d0 ;height
- moveq #16,d1 ;width
- moveq #0,d2 ;xoffset
- moveq #0,d3 ;yoffset
- just SetPointer
- .end_blank bset #STB_MBlanked,Status(a5)
- .no_blank popm.l a0-a1/a6/d0-d3
- rts
-
- ;*»» Restore old mouse image
- ; Takes a5=GlobalPtr; IBase must be locked; Scratches nil
- RestoreMouse:
- pushm.l a0-a1/a6/d0-d3
- move.l IntBase(a5),a6
- move.l MBlankWindow(a5),d0
- bne.s .knownblnk ; If nothing is apparently blanked then
- .unknwnblnk move.l ib_ActiveWindow(a6),d0 ; Try the active window
- beq.s .end_RMouse ; (quit if no active window)
- move.l d0,a0
- clr.l OldPointer+Ptr_Image(a5) ;(whose image we don't know)
- bra.s .foundwind
- .knownblnk move.l MBlankScreen(a5),d2 ; We know it's on this screen
- move.l ib_FirstScreen(a6),d1 ; Start with the first screen
- .screenloop beq.s .end_RMouse ; While screen^ =/= NULL
- move.l d1,a0 ; Get ^ into address reg
- cmp.l d1,d2 ; Compare screen to target
- beq.s .foundscrn ; Exit if found target screen
- move.l sc_NextScreen(a0),d1 ; Get next screen
- bra.s .screenloop ; End while
- .foundscrn move.l sc_FirstWindow(a0),d1 ; Start with first window
- .windowloop beq.s .end_RMouse ; While window^ =/= NULL
- move.l d1,a0
- cmp.l d0,d1 ; Compare window with target
- beq.s .foundwind ; Exit if this is the window
- move.l wd_NextWindow(a0),d1 ; Next window
- bra.s .windowloop ; End while
- .foundwind ; We now know window exists and that a0=^window
- move.l wd_Pointer(a0),d0
- cmp.l MouseChipData(a5),d0
- bne.s .end_RMouse ; Skip if already unblanked
- move.l OldPointer+Ptr_Image(a5),a1
- move.l a1,d0
- bne.s .restoreold ; If no image pointer then
- just ClearPointer ; Restore default pointer
- bra.s .end_RMouse ; Else
- .restoreold move.b OldPointer+Ptr_Height(a5),d0
- move.b OldPointer+Ptr_Width(a5),d1
- move.b OldPointer+Ptr_XOffset(a5),d2
- move.b OldPointer+Ptr_YOffset(a5),d3
- ext.w d0
- ext.w d1
- ext.w d2
- ext.w d3
- just SetPointer ; Restore custom pointer
- .end_RMouse bclr #STB_MBlanked,Status(a5)
- popm.l a0-a1/a6/d0-d3
- rts
-
- ***************************************************************************
-
- GlobalPtr: ds.l 1
-
- NorthgateTable:
- ;*»» Assign PageUp/PageDown/Home/End to shift-cursor sequences
- dc.b $6b,$4f,IEQUALIFIER_LSHIFT
- dc.b $6c,$4e,IEQUALIFIER_LSHIFT
- dc.b $6d,$4c,IEQUALIFIER_LSHIFT
- dc.b $6e,$4d,IEQUALIFIER_LSHIFT
- ; ;*»» Change a couple keypad key assignments to be more Amiga-like.
- ; dc.b $5c,$5b,0 ;'/' key -> ')' key
- ; dc.b $5d,$5c,0 ;'*' key -> '/' key
- ; dc.b $4a,$5d,0 ;'-' key -> '*' key
- dc.b 0
-
- ProcName: dc.b 'Funky baby Mouse process 1.2',0 ;»» Name of child process
- InitialLetter equ 'F' ;»» child's first initial
- InputName: dc.b 'input.device',0
- NilName: dc.b 'NIL:',0
- even
-
- NewProcTags: ; In allocated memory so command can be pure
- dc.l NP_Entry
- EntryPointTag equ *-NewProcTags
- dc.l 0
- dc.l NP_Name
- ProcNameTag equ *-NewProcTags
- dc.l 0
- dc.l NP_Cli,-1
- dc.l NP_Priority,TaskPriority
- dc.l 0 ;end of tags
-
- ***************************************************************************
- EndResidentCode: ;end of code copied into allocated memory
- ***************************************************************************
- ***************************************************************************
- ResidentCodeLength equ EndResidentCode-StartResidentCode
-
-
- ***************************************************************************
- * Global data and constants
- ***************************************************************************
-
- HANDLERPRI equ 100 ;Higher than pesky AMOS
- TaskPriority equ 20
- ShellPriority equ 0
-
- NULL equ 0
- KEYCODE_ESC equ $45
-
- BITDEF BB,TOP,0
- BITDEF BB,BOTTOM,1
- BITDEF BB,LEFT,2
- BITDEF BB,RIGHT,3
-
- DosName dc.b "dos.library",0
- IntName dc.b "intuition.library",0
- LayName dc.b "layers.library",0
-
- ;*****************************************************************
- ;* Global data structure definitions
-
- STRUCTURE PointerStruct,0
- APTR Ptr_Image
- LABEL Ptr_Dimensions
- BYTE Ptr_Height
- BYTE Ptr_Width
- BYTE Ptr_XOffset
- BYTE Ptr_YOffset
- LABEL Ptr_SIZEOF
-
- wd_PtrDimensions equ wd_PtrHeight
-
- STRUCTURE Data,0
- APTR MouseChipData
- LABEL FirstLibBase
- APTR DosBase
- APTR IntBase
- APTR LayBase
-
- LABEL Sigs
- LONG CLISig
- LONG UpdateSig
- LONG MouseBlankSig
- LONG ScreenDepthSig
- LONG CloseScreenSig
- LABEL EndSigs
- NumSigs equ (EndSigs-Sigs)/4
- LONG AllSignals ;Logical OR of all signals
-
- APTR Task
- APTR ArgPtr
- LABEL OldRoutines
- APTR OldDisplayBeep
- APTR OldCloseScreen
- APTR OldScreenDepth
- LONG MouseTime ;timeout for mouse blanking
- APTR MBlankWindow
- APTR MBlankScreen
- STRUCT OldPointer,Ptr_SIZEOF
- LONG ScreenTime ;for screen blanking
- APTR ClickWindow
- LONG ClickCount
- STRUCT ClickTime,TV_SIZE
- APTR InputMsgPort
- APTR InputIORequest
-
- Template: dc.b 'M=MBLANK/K/N,'
- dc.b 'S=SBLANK/K/N,'
- dc.b 'A=ACCELERATION/K/N,'
- dc.b 'T=THRESHOLD/K/N,'
- dc.b 'CTF=CLICKTOFRONT/K/N,'
- dc.b 'CTFB=CLICKTOFRONTBORDER/K/N,'
- dc.b 'CTB=CLICKTOBACK/S,'
- dc.b 'AFS=ACTIVATEFRONTSCREEN/S,'
- dc.b 'CMD=COMMAND/K,'
- dc.b 'SUNMOUSE/S,'
- dc.b 'NORTHGATE/S,'
- dc.b 'NOBEEP/S'
- dc.b 0
-
- LABEL Options
- LONG MBlankOption
- LONG SBlankOption
- LONG AccelOption
- LONG ThreshOption
- LONG CTFOption
- LONG ClickBorderOption
- LONG CTBOption
- LONG ActivateScreenOption
- LONG CmdOption
- LONG SunMouseOption
- LONG NorthgateOption
- LONG NoBeepOption
- LABEL EndOptions
- NumOptions equ (EndOptions-Options)/4
-
- LABEL OptionCaches
- LONG MouseBlank
- LONG ScreenBlank
- LONG Acceleration ; Copies of parameters
- LONG Threshold ; ..to avoid having to wait on semaphore
- LONG CTF ; ..which could deadlock input handler
- LONG CTFB
-
- STRUCT InputInterrupt,IS_SIZE
- STRUCT MySemaphore,SS_SIZE
- STRUCT ScreenTable,ST_SIZEOF
- WORD CurrentX
- WORD CurrentY
- WORD DampingConstant
- BYTE Status ; Various status bits (defined below)
- BYTE Padding ; To fill out to even number of bytes
-
- STRUCT ResidentCode,ResidentCodeLength
- LABEL Data_SIZEOF
-
- ;Bit definitions for Status
- BITDEF ST,SBlanked,0
- BITDEF ST,MBlanked,1
- BITDEF ST,SunMouse,2
- BITDEF ST,HandlerInstalled,3
- BITDEF ST,InputDeviceOpened,4
- BITDEF ST,DoMBlank,5
-
- STRUCTURE MouseData,12
- LABEL MouseData_SIZEOF
-
- END